Clonage d’objet en .NET (C# ou VB)
23 11 2011Si vous débarquez en .NET (ou en Java d’ailleurs) et que vous venez d’un bon langage pas casse couille comme PHP ou JavaScript, ça doit vous faire un choc :
Donner un type à ses variables, choisir parmi 36000 structures pour stocker l’information (Array, List, Hasttable, Dictionary, DataTable…), devoir importer des tonnes de trucs pour simplement trier un tableau par ordre décroissant…
Mais le pire, c’est sans doute le passage par référence. En PHP, pour dupliquer une variable (qu’elle soit un simple entier ou un objet très élaboré issu d’une classe que vous avez créé), il suffit d’utiliser = comme pour n’importe quelle affectation :
<?php $variable_originale = new MaClasse(); $variable_originale->nom = "Variable originale"; $copie = $variable_originale; $copie->nom = 'Une copie conforme et parfaitement disctince de $variable_originale'; echo $variable_originale->nom; // Variable originale echo $copie->nom; // Une copie conforme et parfaitement disctince de $variable_originale ?>
Mais en .NET, tout est passé par référence (sauf les types primitifs comme integer, boolean, string… qui eux sont passé par valeur), ça signifie que si vous faites la même chose qu’en PHP ci-dessus, quand vous allez modifier la variable copie, ça va aussi modifie variable_originale. Pourquoi ? Tout simplement parce que copie et variable_originale sont des pointeurs vers la même variable en mémoire, c’est en quelque sorte 2 noms différents pour la même variable.
La solution, pour dupliquer une variable, c’est de créer copie (en appelant le constructeur de MaClasse : copie = new MaClasse()), mais il faut alors recopier un par un la valeur de chaque attribut de variable_originale dans l’attribut de copie homonyme, l’enfer. En général on fait cela en créant une méthode Clone() dans la classe de la variable qu’on veut dupliquer, et en implémentant une interface de clonage comme ICloneable en .NET. C’est au développeur d’implémenter la fonction Clone().
Heureusement, il existe une solution toute bête pour créer une fonction Clone facilement : elle consiste à sérialiser la variable à dupliquer, puis à la desérialiser (ce qui reviendrait à faire un $copie = unserialize(serialize($variable_originale));
en PHP).
Voici donc une fonction permettant de cloner un objet en VB.NET (mais ça marche aussi en C#, il suffit d’adapter la syntaxe) :
Namespace Espace <Serializable()> Friend Class AgriVar Friend Sub New() '[...] End Sub Public Function Clone() Dim memStream As MemoryStream = New MemoryStream() Dim bnFormat As BinaryFormatter = New BinaryFormatter(Nothing, New StreamingContext(StreamingContextStates.Clone)) bnFormat.Serialize(memSteam, Me) memStream.Seek(0, SeekOrigin.Begin) Return bnFormat.Deserialize(memStream) End Function End Class End Namespace
Notez que j’ai écrit <Serializable()>
juste devant le nom de ma classe, ne me demandez pas pourquoi, sans ça ça ne marche pas, il se produit une erreur “Le type XXX n’est pas marqué comme sérialisable”.